﻿#pragma once

#include "Any.h"
#include "Logging.h"
#include "Parser.h"
#include <map>
#include <type_traits>

using linb::any_cast;


struct PointType
{
};

struct ValueType
{
};

template<typename T>
struct Trait
{
  using type = T;
};

class Configuration
{

public:
  Configuration(){};
  ~Configuration(){};


  template<typename T>
  void Add(const std::string& name, const T& value)
  {
    if (Have(name))
    {
      Error(name, "已经存在");
    }
    _parameters[name] = value;
  }

  template<typename T>
  void Set(const std::string& name, const T& value)
  {
    _parameters[name] = value;
  }

  template<typename T>
  std::enable_if_t<std::is_pointer<T>::value, T> Get_(const std::string& name) const
  {
    if (HaveInSelf(name))
    {
      T pointer = linb::any_cast<T>(_parameters.at(name));
      if (pointer == nullptr)
      {
        Error("空指针");
      }
      return pointer;
    }
    Error(name, "不存在");
  }

  template<typename T>
  std::enable_if_t<!std::is_pointer<T>::value, T> Get_(const std::string& name) const
  {
    std::string parser_name = "_parser";

    if (HaveInSelf(name))
    {
      return linb::any_cast<T>(_parameters.at(name));
    }
    else if (HaveInSelf(parser_name))
    {
      Parser* parser = linb::any_cast<Parser*>(_parameters.at(parser_name));
      return parser->Get<T>(name);
    }
    Error(name, "不存在");
  }

  template<typename T>
  T Get(const std::string& name) const
  {
    return Get_<T>(name);
  }

  template<typename T>
  std::vector<T> GetVectorValue(const std::string& name) const
  {
    std::string parser_name = "_parser";

    if (HaveInSelf(name))
    {
      return linb::any_cast<std::vector<T>>(_parameters.at(name));
    }
    else if (HaveInSelf(parser_name))
    {
      Parser* parser = linb::any_cast<Parser*>(_parameters.at(parser_name));
      return parser->GetVectorValue<T>(name);
    }
    Error(name, "不存在");
  }

  template<typename T>
  T Get(const std::string& name, const T& value) const
  {
    bool is_pointer = std::is_pointer<T>::value;
    std::string parser_name = "_parser";

    if (is_pointer)
    {
      Error("不支持指针类型取默认值");
    }

    if (HaveInSelf(name))
    {
      return linb::any_cast<T>(_parameters.at(name));
    }
    else if (HaveInSelf(parser_name))
    {
      Parser* parser = linb::any_cast<Parser*>(_parameters.at(parser_name));
      if (parser->Have(name))
        return parser->Get<T>(name);
      else
        return value;
    }
    else
    {
      return value;
    }
  }

  bool Have(const std::string& name) const;
  bool HaveInSelf(const std::string& name) const;
  bool HaveInParser(const std::string& name) const;

private:
  std::map<std::string, linb::any> _parameters;
};
